home *** CD-ROM | disk | FTP | other *** search
/ QRZ! Ham Radio 4 / QRZ Ham Radio Callsign Database - Volume 4.iso / files / amiga / 7pl204am.lzh / 7PLUS204 / SOURCE / UTILS.C < prev   
Encoding:
C/C++ Source or Header  |  1992-11-22  |  30.3 KB  |  1,515 lines

  1. #include "7plus.h"
  2. #include "globals.h"
  3.  
  4. #ifdef __unix__
  5.  #ifdef __M_XENIX__
  6.   struct utimbuf {
  7.    time_t actime;
  8.    time_t modtime;
  9.   };
  10.   extern time_t mktime (struct tm *utm);
  11.  #else
  12.   #include <utime.h>
  13.  #endif
  14. #endif
  15.  
  16. #ifdef _AMIGA_
  17.  struct utimbuf {
  18.    time_t actime;
  19.    time_t modtime;
  20.  };
  21.  extern time_t mktime (struct tm *utm);
  22. #endif
  23.  
  24. static char no[] = NO, yes[] = YES, always[] = ALWAYS;
  25.  
  26. /*
  27. *** get a line from file. don't care about type of line separator.
  28. ***
  29. ***
  30.  */
  31.  
  32. char *my_fgets (char *string, register n, FILE *rein)
  33. {
  34.   register in, i;
  35.  
  36.   if (feof (rein))
  37.     return (NULL);
  38.  
  39.   i = 0;
  40.   while ((in = fgetc (rein)) != EOF)
  41.   {
  42.     if (in == 0x0d)
  43.     {
  44.       if ((in = fgetc (rein)) != 0x0a)
  45.         if (in != EOF)
  46.           ungetc (in, rein);
  47.       in = 0x0a;
  48.     }
  49.     string[i++] = (char) in;
  50.     if (i == n || in == 0x0a)
  51.       break;
  52.   }
  53.   string[i] = EOS;
  54.   return (string);
  55.  
  56. /*
  57. ***
  58. *** Write a byte to file.
  59. ***
  60.  */
  61.  
  62. int my_putc (int outchar, FILE *out)
  63. {
  64.   register x;
  65.  
  66.   if ((x = putc ((char) outchar, out)) == EOF)
  67.   {
  68.     printf ("\007\nWrite error! Can't continue.\n");
  69.     exit (1);
  70.   }
  71.   return (x);
  72. }
  73.  
  74. /*
  75. *** Get crc and line number from code line.
  76. ***
  77. ***
  78.  */
  79.  
  80. void crc_n_lnum (uint *crc, int *linenumber, char *line)
  81. {
  82.   register ulong cs;
  83.  
  84.   cs = 0xb640L * decode[(byte)line[66]] +
  85.        0xd8L   * decode[(byte)line[65]] +
  86.                  decode[(byte)line[64]];
  87.  
  88.   *linenumber = (int) (cs >> 14);   /* upper 9 bits are the line number */
  89.   *crc = (uint) (cs & 0x3fffL);     /* lower 14 bits are the CRC */
  90. }
  91.  
  92. /*
  93. *** Get crc2 from code line.
  94. ***
  95. ***
  96.  */
  97.  
  98. void crc2 (uint *crc, char *line)
  99. {
  100.  
  101.   *crc = 0xd8 * decode[(byte)line[68]] +
  102.                 decode[(byte)line[67]];
  103. }
  104.  
  105. /*
  106. *** Whip up 2nd CRC
  107. ***
  108. ***
  109.  */
  110.  
  111. void add_crc2 (char *line)
  112. {
  113.   register uint crc;
  114.   register int i;
  115.  
  116.   /* Whip up 2nd CRC */
  117.   crc = 0;
  118.   for (i=66;i>-1;i--)
  119.     crc = crctab[crc>>8] ^ (((crc&255)<<8) | (byte) line[i]);
  120.   crc &= 0x7fff;
  121.  
  122.   i = 67;
  123.   line[i++] = code[crc % 0xd8];
  124.   line[i++] = code[crc / 0xd8];
  125.   line[i] = EOS;
  126. }
  127.  
  128. /*
  129. *** mini-crc for header. safe enough...
  130. ***
  131. ***
  132.  */
  133.  
  134. int mcrc (char *line, int flag)
  135. {
  136.   register int i, j;
  137.   register uint crc;
  138.   char test[3], *p;
  139.  
  140.   sprintf (test, "\xb0\xb1");
  141.  
  142.   if ((p = strstr (line, test)) == NULL)
  143.     return (0);
  144.  
  145.   j = (int) (p - line) + 4;
  146.  
  147.   for (i=crc=0; i<j; i++)
  148.     crc = crctab[crc>>8] ^ (((crc&255)<<8) | (byte)line[i]);
  149.   crc %= 216;
  150.   if (!flag)
  151.   {
  152.     if (crc == (uint) decode[(byte)line[j]])
  153.       return (1);
  154.     else
  155.       return (0);
  156.   }
  157.   else
  158.     line[j] = code[(byte)crc];
  159.  
  160.   return (crc);
  161. }
  162.  
  163. /*
  164. *** read info from indexfile
  165. ***
  166. ***
  167.  */
  168.  
  169. int read_index (FILE *ifile, struct m_index *index)
  170. {
  171.   int j;
  172.   ulong i, begin, end;
  173.  
  174.   #ifdef _CHSIZE_OK
  175.    fseek (ifile, -4L, SEEK_END);
  176.    fseek (ifile, read_ulong (ifile), SEEK_SET);
  177.   #endif
  178.  
  179.   /* clear index */
  180.   for (j = 0;j < 4080; j++)
  181.     index->lines_ok[j] = 0UL;
  182.  
  183.   my_fgets (index->full_name, 12, ifile);
  184.   if (strcmp(index->full_name, "7PLUS-index\x0a"))
  185.   {
  186.     printf ("\007No index info found.\n");
  187.     return (1);
  188.   }
  189.   my_fgets (index->filename, 13, ifile);
  190.   index->filename[(int)strlen(index->filename)-1] = EOS;
  191.   my_fgets (index->full_name, 257, ifile);
  192.   index->full_name[(int)strlen(index->full_name)-1] = EOS;
  193.   index->timestamp = read_ulong (ifile);
  194.   index->splitsize = read_uint  (ifile);
  195.   index->lines_left= (long) read_ulong (ifile);
  196.  
  197.   /* convert defect list into bitvektor */
  198.   while (1==1)
  199.   {
  200.     if ((begin = read_ulong (ifile)) == 0xffffffffUL)
  201.       break;
  202.     end = read_ulong (ifile);
  203.  
  204.     if ((end>>5) > (begin>>5))
  205.       for (i = begin;i < ((begin |31UL) + 1UL); i++)
  206.         index->lines_ok[(int)i>>5] |= (1UL <<(i&31UL));
  207.     else
  208.     {
  209.       for (i = begin;i < end; i++)
  210.         index->lines_ok[(int)i>>5] |= (1UL <<(i&31UL));
  211.       continue;
  212.     }
  213.  
  214.     for (i = (begin>>5) +1; i < (end>>5); i++)
  215.       index->lines_ok[(int)i] = 0xffffffffUL;
  216.  
  217.     if (end&31)
  218.       for (i = end &0xffffffe0UL; i < end; i++)
  219.         index->lines_ok[(int)i>>5] |= (1UL <<(i&31UL));
  220.   }
  221.   index->length = read_ulong (ifile);
  222.  
  223.   #ifdef _CHSIZE_OK
  224.    fseek (ifile, 0UL, SEEK_SET);
  225.   #endif
  226.  
  227.   return (0);
  228. }
  229.  
  230. /*
  231. *** write info to indexfile
  232. ***
  233. ***
  234.  */
  235.  
  236. int write_index (FILE *ifile, struct m_index *index, int flag)
  237. {
  238.   int j, part, prevpart, lines;
  239.   ulong i, begin, end;
  240.  
  241.   part = prevpart = lines = 0;
  242.   begin = end = 0UL;
  243.  
  244.   if (!flag)
  245.   {
  246.     #ifdef _CHSIZE_OK
  247.      fseek (ifile, index->length, SEEK_SET);
  248.     #endif
  249.  
  250.     fprintf (ifile, "7PLUS-index\n");
  251.     fprintf (ifile, "%s\n", index->filename);
  252.     fprintf (ifile, "%s\n", index->full_name);
  253.     write_ulong (ifile, index->timestamp);
  254.     write_uint  (ifile, index->splitsize);
  255.     write_ulong (ifile, (ulong) index->lines_left);
  256.   }
  257.   /* convert bitvektor into defect list */
  258.   i = 0UL;
  259.   j = 0;
  260.   while (1==1)
  261.   {
  262.     while (j < 4080 && !(index->lines_ok[j] &(1UL <<(i & 31UL))))
  263.     {
  264.       if (!(i&31UL) && index->lines_ok[j] == 0UL)
  265.       {
  266.         j++;
  267.         i = (ulong) j<<5;
  268.       }
  269.       else
  270.       {
  271.         i++;
  272.         j = (int) i>>5;
  273.       }
  274.     }
  275.  
  276.     if (j == 4080)
  277.       break;
  278.  
  279.     begin = i;
  280.  
  281.     do
  282.     {
  283.       if (!(i&31UL) && index->lines_ok[j] == 0xffffffffUL)
  284.       {
  285.         j++;
  286.         i = (ulong) j<<5;
  287.       }
  288.       else
  289.       {
  290.         i++;
  291.         j = (int) i>>5;
  292.       }
  293.     }
  294.     while (j < 4080 && (index->lines_ok[j] &(1UL <<(i & 31UL))));
  295.  
  296.     end = i;
  297.  
  298.     if (!flag)
  299.     {
  300.       write_ulong (ifile, begin);
  301.       write_ulong (ifile, end);
  302.     }
  303.     else
  304.     {
  305.       for (i = begin; i < end; i++)
  306.       {
  307.         part = (int) i / index->splitsize +1;
  308.         if (part != prevpart)
  309.         {
  310.           if (prevpart)
  311.           {
  312.             if (!(lines % 18) && lines)
  313.               fprintf (ifile, delimit);
  314.             lines = 0;
  315.             fprintf (ifile, "FFF%s", delimit);
  316.           }
  317.           prevpart = part;
  318.           fprintf (ifile, "%02X%s", part, delimit);
  319.         }
  320.  
  321.         lines++; /* Number of missing or corrupted lines in this part. */
  322.         fprintf (ifile, "%03X", (uint)(i % index->splitsize));
  323.         if (!(lines % 18) && lines)
  324.         {
  325.           fprintf (ifile, delimit);
  326.           lines = 0;
  327.         }
  328.         else
  329.           fprintf (ifile, " ");
  330.       }
  331.     }
  332.   }
  333.  
  334.   if (!flag)
  335.   {
  336.     write_ulong (ifile, 0xffffffffUL);
  337.     write_ulong (ifile, index->length);
  338.     #ifdef _CHSIZE_OK
  339.      chsize (fileno (ifile), ftell (ifile));
  340.     #endif
  341.   }
  342.   else
  343.   {
  344.     if (!(lines % 18) && lines)
  345.       fprintf (ifile, delimit);
  346.     fprintf (ifile, "FFF%s", delimit);
  347.   }
  348.   return (0);
  349. }
  350.  
  351. /*
  352. *** Reading/writing unsigned long(32bit)/int(16)
  353. ***
  354. ***
  355.  */
  356.  
  357. ulong read_ulong (FILE *in)
  358. {
  359.   return ((ulong)fgetc (in)       +
  360.          ((ulong)fgetc (in) <<8 ) +
  361.          ((ulong)fgetc (in) <<16) +
  362.          ((ulong)fgetc (in) <<24));
  363. }
  364.  
  365. uint read_uint (FILE *in)
  366. {
  367.   return ((uint)fgetc (in)       +
  368.          ((uint)fgetc (in) <<8 ));
  369. }
  370.  
  371. void write_ulong (FILE *out, ulong val)
  372. {
  373.   my_putc ((int) (val     &0xffUL), out);
  374.   my_putc ((int)((val>>8 )&0xffUL), out);
  375.   my_putc ((int)((val>>16)&0xffUL), out);
  376.   my_putc ((int)((val>>24)&0xffUL), out);
  377. }
  378.  
  379. void write_uint (FILE *out, uint val)
  380. {
  381.   my_putc ((int) (val    &0xffU), out);
  382.   my_putc ((int)((val>>8)&0xffU), out);
  383. }
  384.  
  385. /*
  386. *** read a file, search for s1, calculate CRC until s2 is found.
  387. *** flag == 1: compare calculated an read CRC.
  388. *** flag == 0: insert CRC into file.
  389.  */
  390.  
  391. int crc_file (char *file, char *s1, char *s2, int flag)
  392. {
  393.   char line[81], *p;
  394.   uint crc, cs;
  395.   int i, j, k;
  396.   FILE *in;
  397.  
  398.   crc = cs = 0;
  399.   p = NULLCP;
  400.  
  401.   if (!(in = fopen (file, OPEN_RANDOM_BINARY)))
  402.   {
  403.     printf (cant, file);
  404.     return (2);
  405.   }
  406.  
  407.   i = (int) strlen (s1);
  408.   k = (int) strlen (s2);
  409.  
  410.   j = 1;
  411.  
  412.   do
  413.   {
  414.     if (my_fgets (line, 80, in) == NULL)
  415.       break;
  416.  
  417.     j = strncmp (line, s1, i);
  418.   }
  419.   while (j);
  420.  
  421.   if (j)
  422.     p = s1;
  423.   else
  424.   {
  425.     p = s2;
  426.     do
  427.     {
  428.       for (i=0;i!=(int)strlen(line);i++)
  429.         crc = crctab[crc>>8] ^ (((crc&255)<<8) | (byte)line[i]);
  430.  
  431.       j = strncmp (line, s2, k);
  432.  
  433.       if (!j)
  434.         continue;
  435.  
  436.       if (my_fgets (line, 80, in) == NULL)
  437.         break;
  438.     }
  439.     while (j);
  440.   }
  441.  
  442.   if (j)
  443.   {
  444.     printf ("\n\007Can't calculate CRC\n");
  445.     printf ("String '%s' not found in '%s'.\nBreak.\n", p, file);
  446.     return (7);
  447.   }
  448.  
  449.   /* evaluate CRC */
  450.   if (flag)
  451.   {
  452.     my_fgets (line, 80, in);
  453.     fclose (in);
  454.     if (!line || strncmp ("CRC ", line, 4))
  455.     {
  456.       printf ("\n'%s': no CRC found.\n(File may be corrupted or from version \
  457. earlier than 7PLUS v1.5)\n", file);
  458.       return (17);
  459.     }
  460.     cs = get_hex (line+4);
  461.     if (cs == crc)
  462.       return (0);
  463.  
  464.     printf ("\007\n'%s' is corrupted. Break.\n", file);
  465.     return (7);
  466.   }
  467.  
  468.   /* insert CRC into file */
  469.   fseek (in, 0UL, SEEK_CUR);
  470.   fprintf (in, "CRC %04X", crc);
  471.   fclose (in);
  472.  
  473.   return (0);
  474. }
  475.  
  476. /*
  477. *** Copy a file.
  478. ***
  479. ***
  480.  */
  481.  
  482. int copy_file (char *to, char *from, ulong timestamp)
  483. {
  484.   FILE *_from, *_to;
  485.   int _char, stat;
  486.  
  487.   stat = 0;
  488.  
  489.   _from = fopen (from, OPEN_READ_BINARY);
  490.   _to   = fopen (to,   OPEN_WRITE_BINARY);
  491.  
  492.   while ((_char = getc (_from)) != EOF)
  493.     if ((stat = putc (_char, _to)) == EOF)
  494.       break;
  495.  
  496.   fclose (_from);
  497.  
  498.  #if defined (__MSDOS__) || (__TOS__)
  499.   if (timestamp)
  500.     set_filetime (_to, timestamp);
  501.  
  502.   fclose (_to);
  503.  #else
  504.   fclose (_to);
  505.  
  506.   if (timestamp)
  507.     set_filetime (to, timestamp);
  508.  #endif
  509.  
  510.   if (stat == EOF)
  511.   {
  512.     printf ("\007\nFatal error. Can't write '%s'! Break.\n", to);
  513.     exit (1);
  514.   }
  515.   return (0);
  516. }
  517.  
  518. /*
  519. *** Replace one file with another
  520. ***
  521. ***
  522.  */
  523.  
  524. void replace (char *old, char *new, ulong timestamp)
  525. {
  526.   unlink (old);
  527.  
  528.   if (rename (new, old))
  529.   {
  530.     copy_file (old, new, timestamp);
  531.     unlink (new);
  532.   }
  533.   else
  534.   {
  535.     if (timestamp)
  536.     {
  537.      #if defined (__MSDOS__) || (__TOS__)
  538.       FILE *_file;
  539.  
  540.       _file = fopen (old, OPEN_APPEND_BINARY);
  541.       set_filetime (_file, timestamp);
  542.       fclose (_file);
  543.      #else
  544.       set_filetime (old, timestamp);
  545.      #endif
  546.     }
  547.   }
  548. }
  549.  
  550. /*
  551. *** Kill all files that aren't needed any more
  552. ***
  553. ***
  554.  */
  555.  
  556. void kill_em (char *name, char *inpath, char *one, char *two,
  557.               char *three, char *four, char *five)
  558. {
  559.   char *p, newname[MAXPATH];
  560.   int i, j, k, len;
  561.  
  562.   k = 0;
  563.  
  564.   for (i = 0; i < 5; i++)
  565.   {
  566.     if (!i)
  567.       printf ("\n");
  568.  
  569.     switch (i)
  570.     {
  571.       case 0:  p = one;
  572.                break;
  573.       case 1:  p = two;
  574.                break;
  575.       case 2:  p = three;
  576.                break;
  577.       case 3:  p = four;
  578.                break;
  579.       case 4:  p = five;
  580.  
  581.       default: p = NULLCP;
  582.     }
  583.     if (!p)
  584.      break;
  585.  
  586.     len = strlen(p);
  587.  
  588.     for (j = 1; j <256; j++)
  589.     {
  590.       if (len == 3)
  591.         sprintf (newname, "%s%s.%s", inpath, name, p);
  592.       else
  593.         sprintf (newname, "%s%s.%s%02x", inpath, name, p, j);
  594.  
  595.       if (unlink (newname))
  596.         break;
  597.  
  598.       k++;
  599.  
  600.       printf ("Deleting: %s\r", newname);
  601.       fflush (stdout);
  602.  
  603.       if (len == 3)
  604.         break;
  605.     }
  606.   }
  607.   if (k)
  608.     printf ("\n");
  609. }
  610.  
  611. /*
  612. ***
  613. ***
  614. ***
  615.  */
  616.  
  617. void kill_dest (FILE *in, FILE *out, char *name)
  618. {
  619.     if (out)
  620.       fclose (out);
  621.     if (in)
  622.       fclose (in);
  623.     if (*name)
  624.       unlink (name);
  625. }
  626.  
  627. /*
  628. ***
  629. ***  test if a file exists at all
  630. ***
  631.  */
  632.  
  633. int test_exist (char *filename)
  634. {
  635.   FILE *in = NULLFP;
  636.  
  637.   if ((in = fopen (filename, OPEN_READ_TEXT)) != NULLFP)
  638.   {
  639.     fclose (in);
  640.     return (0);
  641.   }
  642.   return (1);
  643. }
  644.  
  645.  
  646. /*
  647. ***  test if outputfile already exists. prompt for overwrite or
  648. ***  new name.
  649. ***
  650.  */
  651.  
  652. int test_file (FILE *in, char *destnam, int flag, int namsize)
  653. {
  654.    FILE *out;
  655.    int  i, ret;
  656.  
  657.    ret = 0;
  658.  
  659.    if (noquery)
  660.      return (ret);
  661.  
  662.    /* Loop as long as file can be opened. */
  663.    while ((out = fopen (destnam, OPEN_READ_BINARY)) != NULLFP)
  664.    {
  665.      ret = 1;
  666.      printf ("\007\nOutputfile '%s' already exists, overwrite? [y/n/a] ", destnam);
  667.      do
  668.      {
  669.        i = getch();
  670.        i = toupper(i);
  671.  
  672.        if (i == 'N')
  673.        {
  674.          if (flag)
  675.          {
  676.            #ifdef _AMIGA_
  677.             printf ("Enter new name (max %d chars)\n", namsize);
  678.             printf ("or press <CNTL>+C <RETURN> to break : ");
  679.  
  680.             if (namsize == 12)
  681.               strlwr (destnam);
  682.  
  683.             scanf("%s",destnam);
  684.             destnam[namsize] = EOS;
  685.            #else
  686.             printf ("%s\nEnter new name (max %d chars)\n", no, namsize);
  687.             printf ("or simply press ENTER to break : ");
  688.  
  689.             if (namsize == 12)
  690.               strlwr (destnam);
  691.  
  692.             i = getc(stdin);
  693.             if(i != '\n')
  694.             {
  695.               ungetc(i, stdin);
  696.               scanf ("%s", destnam);
  697.               fflush (stdin);
  698.             }
  699.             else
  700.               destnam[0] = EOS;
  701.             destnam[namsize] = EOS;
  702.            #endif
  703.          }
  704.          else
  705.            *destnam = EOS;
  706.          if (!strlen (destnam))
  707.          {
  708.            if (!flag)
  709.              printf ("%s\n", no);
  710.            printf ("Break.\n");
  711.            if (in)
  712.              fclose (in);
  713.            exit (10);
  714.          }
  715.          i = 0xff; /* indicate, that new name has been specified */
  716.        }
  717.      }
  718.      while (i != 'Y' && i != 'A' && i != 0xff);
  719.  
  720.      if (i != 0xff)
  721.      {
  722.        if (i == 'A')
  723.        {
  724.          printf ("%s\n", always);
  725.          noquery = 1;
  726.        }
  727.        else
  728.          printf ("%s\n", yes);
  729.      }
  730.      printf ("\n");
  731.  
  732.      fclose (out);
  733.  
  734.      if (i != 0xff)
  735.        break;
  736.    }
  737.  
  738.    return (ret);
  739. }
  740.  
  741.  
  742. /*
  743. *** initialize decoding table
  744. ***
  745. ***
  746.  */
  747.  
  748. void init_decodetab (void)
  749. {
  750.   register i;
  751.   register byte j;
  752.  
  753.   for (i = 0; i < 256; i++)
  754.     decode[i] = 255;
  755.  
  756.   j = 0;
  757.   for (i = 0x21; i < 0x2a; i++)
  758.     decode[i] = j++;
  759.  
  760.   for (i = 0x2b; i < 0x7f; i++)
  761.     decode[i] = j++;
  762.  
  763.   for (i = 0x80; i < 0x91; i++)
  764.     decode[i] = j++;
  765.  
  766.   decode[0x92] = j++;
  767.  
  768.   for (i = 0x94; i < 0xfd; i++)
  769.     decode[i] = j++;
  770. }
  771.  
  772. /*
  773. *** initialize encoding table
  774. ***
  775. ***
  776.  */
  777.  
  778. void init_codetab (void)
  779. {
  780.   register byte i, j;
  781.  
  782.   j = 0;
  783.  
  784.   for (i = 0x21; i < 0x2a; i++, j++)
  785.     code[j] = i;
  786.  
  787.   for (i = 0x2b; i < 0x7f; i++, j++)
  788.     code[j] = i;
  789.  
  790.   for (i = 0x80; i < 0x91; i++, j++)
  791.     code[j] = i;
  792.  
  793.   code[j++] = 146;
  794.  
  795.   for (i = 0x94; i < 0xfd; i++, j++)
  796.     code[j] = i;
  797. }
  798.  
  799. /*
  800. *** Tnx to DC4OX.
  801. ***
  802. *** calculate CRC-table
  803. ***
  804.  */
  805.  
  806. void init_crctab (void)
  807. {
  808.   uint m, n, r, mask;
  809.  
  810.   static uint bitrmdrs[] = { 0x9188,0x48C4,0x2462,0x1231,
  811.                              0x8108,0x4084,0x2042,0x1021 };
  812.  
  813.   for (n = 0; n < 256; ++n)
  814.   {
  815.     for (mask = 0x0080, r = 0, m = 0; m < 8; ++m, mask >>= 1)
  816.       if (n & mask)
  817.         r = bitrmdrs[m] ^ r;
  818.     crctab[n] = r;
  819.   }
  820. }
  821.  
  822. /*
  823. *** Create a MSDOS/ATARI compatible filename.
  824. ***
  825. ***
  826.  */
  827.  
  828. void build_DOS_name (char *name)
  829. {
  830.   char tmp[MAXFNAME];
  831.   register i, j;
  832.  
  833.   i = j = 0;
  834.  
  835.   strcpy (tmp, name);
  836.   strlwr (tmp);
  837.  
  838.   if (*tmp)
  839.   {
  840.     do
  841.     {
  842.       tmp[i] &= 127;
  843.       if (strchr (" <>=,;:*?&[]()/.\\\"~+@", tmp[i]) == NULL)
  844.         name[j++] = tmp[i];
  845.     }
  846.     while (tmp[++i]);
  847.  
  848.     name[j] = EOS;
  849.   }
  850. }
  851.  
  852. #if defined (__MSDOS__) || (__TOS__)
  853.  /*
  854.  *** Get file's timestamp and package it into a 32-bit word (MS_DOS-format)
  855.  ***
  856.  ***
  857.   */
  858.  ulong get_filetime (FILE *_file)
  859.  {
  860.   ulong    ftimestamp;
  861.  
  862.   if (getftime (fileno(_file), (struct ftime *)&ftimestamp) == EOF)
  863.     printf ("\007\nCan't get file's timestamp!\n");
  864.  
  865.  #ifdef __TOS__
  866.   ftimestamp = swapl(ftimestamp);
  867.  #endif
  868.  
  869.   return (ftimestamp);
  870.  }
  871.  
  872.  #define _SETFTIME_OK
  873.  /*
  874.  *** Set file's timestamp
  875.  ***
  876.  ***
  877.   */
  878.  void set_filetime (FILE *_file, ulong ftimestamp)
  879.  {
  880.  #ifdef __TOS__
  881.   ftimestamp = swapl(ftimestamp);
  882.  #endif
  883.  
  884.   if (setftime (fileno(_file), (struct ftime *)&ftimestamp) == EOF)
  885.     printf ("\007\nCan't set file's timestamp!");
  886.  }
  887.  
  888. #else /* it's not an MSDOS or Atari system */
  889.  #ifndef _HAVE_GMTIME
  890.   /*
  891.   * mktime function from GNU C library V1.03; modified:
  892.   * - expanded DEFUN and CONST macros from ansidecl.h
  893.   * - inserted __isleap macro from time.h
  894.   * - inserted __mon_lengths array and __offtime function from offtime.c
  895.   * - inserted gmtime function from gmtime.c
  896.   * - commented out call of localtime function
  897.   * Be aware of the following copyright message for mktime !!!
  898.   */
  899.  
  900.   /* Copyright (C) 1991 Free Software Foundation, Inc.
  901.   This file is part of the GNU C Library.
  902.  
  903.   The GNU C Library is free software; you can redistribute it and/or
  904.   modify it under the terms of the GNU Library General Public License as
  905.   published by the Free Software Foundation; either version 2 of the
  906.   License, or (at your option) any later version.
  907.  
  908.   The GNU C Library is distributed in the hope that it will be useful,
  909.   but WITHOUT ANY WARRANTY; without even the implied warranty of
  910.   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  911.   Library General Public License for more details.
  912.  
  913.   You should have received a copy of the GNU Library General Public
  914.   License along with the GNU C Library; see the file COPYING.LIB.  If
  915.   not, write to the Free Software Foundation, Inc., 675 Mass Ave,
  916.   Cambridge, MA 02139, USA.  */
  917.  
  918.  
  919.   /* How many days are in each month.  */
  920.   const unsigned short int __mon_lengths[2][12] =
  921.     {
  922.       /* Normal years.  */
  923.       { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 },
  924.       /* Leap years.  */
  925.       { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }
  926.     };
  927.  
  928.   #define  __isleap(year)  \
  929.     ((year) % 4 == 0 && ((year) % 100 != 0 || (year) % 400 == 0))
  930.  
  931.   #define  invalid()  return (time_t) -1
  932.  
  933.  
  934.   #define  SECS_PER_HOUR  (60 * 60)
  935.   #define  SECS_PER_DAY  (SECS_PER_HOUR * 24)
  936.  
  937.   /* Returns the `struct tm' representation of *T,
  938.      offset OFFSET seconds east of UCT.  */
  939.   struct tm *
  940.   __offtime (const time_t *t, long int offset)
  941.   {
  942.     static struct tm tbuf;
  943.     register long int days, rem;
  944.     register int y;
  945.     register const unsigned short int *ip;
  946.  
  947.     if (t == NULL)
  948.       return NULL;
  949.  
  950.     days = *t / SECS_PER_DAY;
  951.     rem = *t % SECS_PER_DAY;
  952.     rem += offset;
  953.     while (rem < 0)
  954.     {
  955.       rem += SECS_PER_DAY;
  956.       --days;
  957.     }
  958.     while (rem >= SECS_PER_DAY)
  959.     {
  960.       rem -= SECS_PER_DAY;
  961.       ++days;
  962.     }
  963.     tbuf.tm_hour = rem / SECS_PER_HOUR;
  964.     rem %= SECS_PER_HOUR;
  965.     tbuf.tm_min = rem / 60;
  966.     tbuf.tm_sec = rem % 60;
  967.     /* January 1, 1970 was a Thursday.  */
  968.     tbuf.tm_wday = (4 + days) % 7;
  969.     if (tbuf.tm_wday < 0)
  970.       tbuf.tm_wday += 7;
  971.     y = 1970;
  972.     while (days >= (rem = __isleap(y) ? 366 : 365))
  973.     {
  974.       ++y;
  975.       days -= rem;
  976.     }
  977.     while (days < 0)
  978.     {
  979.       --y;
  980.       days += __isleap(y) ? 366 : 365;
  981.     }
  982.     tbuf.tm_year = y - 1900;
  983.     tbuf.tm_yday = days;
  984.     ip = __mon_lengths[__isleap(y)];
  985.     for (y = 0; days >= ip[y]; ++y)
  986.       days -= ip[y];
  987.     tbuf.tm_mon = y;
  988.     tbuf.tm_mday = days + 1;
  989.     tbuf.tm_isdst = -1;
  990.  
  991.     return &tbuf;
  992.   }
  993.  
  994.  
  995.   /* Return the `struct tm' representation of *T in UTC.  */
  996.   struct tm *
  997.   gmtime (const time_t *t)
  998.   {
  999.     return __offtime(t, 0L);
  1000.   }
  1001.  #endif /* ifndef _HAVE_GMTIME */
  1002.  
  1003.  #ifndef _HAVE_MKTIME
  1004.  
  1005.   /* Return the `time_t' representation of TP and normalizes TP.
  1006.      Return (time_t) -1 if TP is not representable as a `time_t'.
  1007.      Note that 31 Dec 1969 23:59:59 is not representable
  1008.      because it is represented as (time_t) -1.  */
  1009.   time_t mktime (register struct tm *tp)
  1010.   {
  1011.     static struct tm min, max;
  1012.     static char init = 0;
  1013.  
  1014.     register time_t result;
  1015.     register time_t t;
  1016.     register int i;
  1017.     register const unsigned short *l;
  1018.     register struct tm *new;
  1019.     time_t end;
  1020.  
  1021.     if (tp == NULL)
  1022.     {
  1023.       errno = EINVAL;
  1024.       invalid();
  1025.     }
  1026.  
  1027.     if (!init)
  1028.     {
  1029.       init = 1;
  1030.       end = (time_t) LONG_MIN;
  1031.       new = gmtime(&end);
  1032.       if (new != NULL)
  1033.         min = *new;
  1034.       else
  1035.         min.tm_sec = min.tm_min = min.tm_hour =
  1036.       min.tm_mday = min.tm_mon = min.tm_year = INT_MIN;
  1037.  
  1038.       end = (time_t) LONG_MAX;
  1039.       new = gmtime(&end);
  1040.       if (new != NULL)
  1041.         max = *new;
  1042.       else
  1043.         max.tm_sec = max.tm_min = max.tm_hour =
  1044.       max.tm_mday = max.tm_mon = max.tm_year = INT_MAX;
  1045.     }
  1046.  
  1047.     /* Make all the elements of TP that we pay attention to
  1048.        be within the ranges of reasonable values for those things.  */
  1049.     #define  normalize(elt, min, max, nextelt)\
  1050.     while (tp->elt < min)                     \
  1051.     {                                         \
  1052.       --tp->nextelt;                          \
  1053.       tp->elt += max + 1;                     \
  1054.     }                                         \
  1055.     while (tp->elt > max)                     \
  1056.     {                                         \
  1057.       ++tp->nextelt;                          \
  1058.       tp->elt -= max + 1;                     \
  1059.     }
  1060.  
  1061.     normalize (tm_sec, 0, 59, tm_min);
  1062.     normalize (tm_min, 0, 59, tm_hour);
  1063.     normalize (tm_hour, 0, 24, tm_mday);
  1064.  
  1065.     /* Normalize the month first so we can use
  1066.        it to figure the range for the day.  */
  1067.     normalize (tm_mon, 0, 11, tm_year);
  1068.     normalize (tm_mday, 1, __mon_lengths[__isleap (tp->tm_year)][tp->tm_mon],
  1069.       tm_mon);
  1070.  
  1071.     /* Normalize the month again, since normalizing
  1072.        the day may have pushed it out of range.  */
  1073.     normalize (tm_mon, 0, 11, tm_year);
  1074.  
  1075.     /* Normalize the day again, because normalizing
  1076.        the month may have changed the range.  */
  1077.     normalize (tm_mday, 1, __mon_lengths[__isleap (tp->tm_year)][tp->tm_mon],
  1078.       tm_mon);
  1079.  
  1080.    /* Check for out-of-range values.  */
  1081.    #define  lowhigh(field, minmax, cmp)  (tp->field cmp minmax.field)
  1082.    #define  low(field)                   lowhigh(field, min, <)
  1083.    #define  high(field)                  lowhigh(field, max, >)
  1084.    #define  oor(field)                   (low(field) || high(field))
  1085.    #define  lowbound(field)              (tp->field == min.field)
  1086.    #define  highbound(field)             (tp->field == max.field)
  1087.    if (oor(tm_year))
  1088.      invalid();
  1089.    else
  1090.      if (lowbound(tm_year))
  1091.      {
  1092.        if (low(tm_mon))
  1093.          invalid();
  1094.        else
  1095.          if (lowbound(tm_mon))
  1096.          {
  1097.            if (low(tm_mday))
  1098.              invalid();
  1099.            else
  1100.              if (lowbound(tm_mday))
  1101.              {
  1102.                if (low(tm_hour))
  1103.                  invalid();
  1104.                else
  1105.                  if (lowbound(tm_hour))
  1106.                  {
  1107.                    if (low(tm_min))
  1108.                      invalid();
  1109.                    else
  1110.                      if (lowbound(tm_min))
  1111.                      {
  1112.                        if (low(tm_sec))
  1113.                        invalid();
  1114.                      }
  1115.                  }
  1116.              }
  1117.          }
  1118.      }
  1119.      else
  1120.        if (highbound(tm_year))
  1121.        {
  1122.          if (high(tm_mon))
  1123.            invalid();
  1124.          else
  1125.            if (highbound(tm_mon))
  1126.            {
  1127.              if (high(tm_mday))
  1128.                invalid();
  1129.              else
  1130.                if (highbound(tm_mday))
  1131.                {
  1132.                  if (high(tm_hour))
  1133.                    invalid();
  1134.                  else
  1135.                    if (highbound(tm_hour))
  1136.                    {
  1137.                      if (high(tm_min))
  1138.                        invalid();
  1139.                      else
  1140.                        if (highbound(tm_min))
  1141.                        {
  1142.                          if (high(tm_sec))
  1143.                          invalid();
  1144.                        }
  1145.                    }
  1146.                }
  1147.            }
  1148.        }
  1149.     t = 0;
  1150.     for (i = 1970; i > 1900 + tp->tm_year; --i)
  1151.       t -= __isleap(i) ? 366 : 365;
  1152.     for (i = 1970; i < 1900 + tp->tm_year; ++i)
  1153.       t += __isleap(i) ? 366 : 365;
  1154.     l = __mon_lengths[__isleap(1900 + tp->tm_year)];
  1155.     for (i = 0; i < tp->tm_mon; ++i)
  1156.       t += l[i];
  1157.     t += tp->tm_mday - 1;
  1158.     result = ((t * 60 * 60 * 24) +
  1159.              (tp->tm_hour * 60 * 60) +
  1160.              (tp->tm_min * 60) +
  1161.               tp->tm_sec);
  1162.  
  1163.     end = result;
  1164.    #if 0
  1165.     if (tp->tm_isdst < 0)
  1166.       new = localtime(&end);
  1167.     else
  1168.    #endif
  1169.       new = gmtime(&end);
  1170.     if (new == NULL)
  1171.       invalid();
  1172.     new->tm_isdst = tp->tm_isdst;
  1173.     *tp = *new;
  1174.  
  1175.     return result;
  1176.   }
  1177.  #endif /* ifndef _HAVE_MKTIME */
  1178.  
  1179.  #ifndef _FTIMEDEFINED
  1180.   /*
  1181.    * these functions have to convert a MS/DOS time to a UNIX time
  1182.    * and vice versa.
  1183.    * here comes the MS/DOS time structure
  1184.    */
  1185.   #ifdef _AMIGA_
  1186.    struct ftime
  1187.      {
  1188.        unsigned  int ft_year  : 7; /* Year minus 1980 */
  1189.        unsigned  int ft_month : 4;   /* 1..12 */
  1190.        unsigned  int ft_day   : 5;   /* 1..31 */
  1191.        unsigned  int ft_hour  : 5;   /* 0..23 */
  1192.        unsigned  int ft_min   : 6;   /* 0..59 */
  1193.        unsigned  int ft_tsec  : 5;   /* 0..59 /2 (!) */
  1194.      };
  1195.   #else
  1196.    struct ftime
  1197.    {
  1198.      unsigned  ft_tsec  : 5;   /* 0..59 /2 (!) */
  1199.      unsigned  ft_min   : 6;   /* 0..59 */
  1200.      unsigned  ft_hour  : 5;   /* 0..23 */
  1201.      unsigned  ft_day   : 5;   /* 1..31 */
  1202.      unsigned  ft_month : 4;   /* 1..12 */
  1203.      unsigned  ft_year  : 7; /* Year minus 1980 */
  1204.    };
  1205.   #endif
  1206.  #endif /* _FTIMEDEFINED */
  1207.  
  1208.  /*
  1209.   * Get file's timestamp and package it into a 32-bit word (MS_DOS-format).
  1210.   * This function should work on any system (even on AMIGAs) :-)
  1211.   */
  1212.  ulong get_filetime (char *filename)
  1213.  {
  1214.    struct ftime fti;
  1215.    ulong *retval = (ulong *) &fti;
  1216.    struct tm *utm;
  1217.    struct stat fst;
  1218.  
  1219.    *retval = 0UL;
  1220.  
  1221.    /* get file status */
  1222.    if (stat (filename, &fst) == 0)
  1223.    {
  1224.       /* get time of last modification and convert it to MS/DOS time */
  1225.      utm = gmtime (&fst.st_mtime);
  1226.  
  1227.      if (utm)
  1228.      {
  1229.        fti.ft_tsec  = utm->tm_sec / 2;
  1230.        fti.ft_min   = utm->tm_min;
  1231.        #ifdef _AMIGA_
  1232.         fti.ft_hour  = utm->tm_hour -6;/* US_TIME_COR */
  1233.        #else
  1234.         fti.ft_hour  = utm->tm_hour;
  1235.        #endif
  1236.        fti.ft_day   = utm->tm_mday;
  1237.        fti.ft_month = utm->tm_mon + 1;
  1238.        fti.ft_year  = utm->tm_year - 80;
  1239.        return (*retval);
  1240.      }
  1241.    }
  1242.  
  1243.    /* error exit */
  1244.    printf ("\007\nCan't get file's timestamp!\n");
  1245.    return (*retval);
  1246.  }
  1247.  
  1248.  #ifdef _AMIGA_
  1249.   #define _SETFTIME_OK
  1250.   /*
  1251.    * Set file's timestamp
  1252.    * This function only works on AMIGA-systems
  1253.    */
  1254.   void set_filetime (char *filename, ulong ftimestamp)
  1255.   {
  1256.     time_t atime;
  1257.     struct ftime *fti;
  1258.     struct tm utm;
  1259.     struct DateStamp fdate;
  1260.     unsigned long zeit;
  1261.     long fday;
  1262.     long fmin;
  1263.     long fsec;
  1264.   
  1265.  
  1266.     /* convert MS/DOS ftimestamp to UNIX atime */
  1267.     fti = (struct ftime *) &ftimestamp;
  1268.     utm.tm_sec   = fti->ft_tsec * 2;
  1269.     utm.tm_min   = fti->ft_min;
  1270.     utm.tm_hour  = fti->ft_hour;
  1271.     utm.tm_mday  = fti->ft_day;
  1272.     utm.tm_mon   = fti->ft_month - 1;
  1273.     utm.tm_year  = fti->ft_year +80;
  1274.     utm.tm_wday  = utm.tm_yday  =  utm.tm_isdst = 0;
  1275.     atime = mktime (&utm);
  1276.     zeit = gmtime(&atime);
  1277.  
  1278.     fday = (atime / 86400);    /* 86400sec per Day + systimecorr.*/
  1279.     fmin = (atime - (fday * 86400)) / 60;
  1280.     fsec = (atime - (fday * 86400) - (fmin * 60));
  1281.     
  1282.     fday = fday -2922;             /* correctur filetime>mktime */
  1283.     fsec = fsec * TICKS_PER_SECOND; /* correctur AMIGA-SYSTEM-TICKS */
  1284.     fdate.ds_Days = fday;
  1285.     fdate.ds_Minute = fmin;
  1286.     fdate.ds_Tick = fsec;
  1287.  
  1288.     SetFileDate(filename,&fdate);
  1289.  
  1290.     return(1);
  1291.   }
  1292.  #endif /* _AMIGA_ */
  1293.  
  1294.  #ifdef __unix__
  1295.   #define _SETFTIME_OK
  1296.   /*
  1297.    * Set file's timestamp
  1298.    * This function only works on UNIX-systems
  1299.    */
  1300.   void set_filetime (char *filename, ulong ftimestamp)
  1301.   {
  1302.     time_t atime;
  1303.     struct utimbuf utim;
  1304.     struct ftime *fti;
  1305.     struct tm utm;
  1306.  
  1307.     /* convert MS/DOS ftimestamp to UNIX atime */
  1308.     fti = (struct ftime *) &ftimestamp;
  1309.     utm.tm_sec   = fti->ft_tsec * 2;
  1310.     utm.tm_min   = fti->ft_min;
  1311.     utm.tm_hour  = fti->ft_hour;
  1312.     utm.tm_mday  = fti->ft_day;
  1313.     utm.tm_mon   = fti->ft_month - 1;
  1314.     utm.tm_year  = fti->ft_year + 80;
  1315.     utm.tm_wday  = utm.tm_yday  =  utm.tm_isdst = 0;
  1316.     atime = mktime (&utm);
  1317.  
  1318.     if (atime != -1)
  1319.     {
  1320.       /* set access time and modification time */
  1321.       utim.actime = atime;
  1322.       utim.modtime = atime;
  1323.       if (utime (filename, &utim) >= 0)
  1324.         return;
  1325.     }
  1326.  
  1327.     /* error exit */
  1328.     printf ("\007\nCan't set file's timestamp!");
  1329.     return;
  1330.   }
  1331.  #endif /* __unix__ */
  1332.  
  1333.  #ifndef _SETFTIME_OK
  1334.   /*
  1335.    * Set file's timestamp
  1336.    *
  1337.    */
  1338.   void set_filetime (char *filename, ulong ftimestamp)
  1339.   {
  1340.     /* error exit */
  1341.     printf ("\007\nset_filetime not (yet) implemented on this system!\n");
  1342.     printf ("7PLUS should NOT be circulated until it is implemented!!\n");
  1343.     printf ("Axel, DG1BBQ.\n");
  1344.     return;
  1345.   }
  1346.  #endif
  1347. #endif /* not __MSDOS__ or __TOS__ */
  1348.  
  1349.  
  1350. /*
  1351. *** get_hex: some compilers have real big trouble when reading hex values from
  1352. ***          a file with fscanf() that have leading zeros! e.g. 00A will be
  1353. ***          read as two separate values (0 and A)! grr!!
  1354. ***          get_hex skips all leading zeros to eliminate the problem.
  1355. ***
  1356.  */
  1357.  
  1358. uint get_hex (char *hex)
  1359. {
  1360.   register i = 0;
  1361.   uint   ret = 0;
  1362.  
  1363.   while (hex[i] == '0')
  1364.     i++;
  1365.   sscanf(hex+i, "%x", &ret);
  1366.   return (ret);
  1367. }
  1368.  
  1369.  
  1370. #ifdef _FNSPLIT
  1371. /*
  1372. ***       filenamesplit
  1373. ***       (by DL1MEN, taken from SP-ST, modified for portability)
  1374. ***
  1375. ***       split filename up into drive, path, name and extension.
  1376. ***
  1377.  */
  1378.  
  1379. void fnsplit(char *pth, char *dr, char *pa, char *fn, char *ft)
  1380. {
  1381.   char drv[MAXDRIVE], pat[MAXDIR], fna[MAXFILE], fty[MAXEXT], tmp[MAXPATH];
  1382.   char *p;
  1383.  
  1384.   strcpy(tmp,pth);
  1385.  
  1386.   if ((p = strchr(tmp,':')) != NULL)
  1387.   {
  1388.     *p++ = EOS;
  1389.     strcpy(drv,tmp);
  1390.   }
  1391.   else
  1392.   {
  1393.     p = tmp;
  1394.     drv[0] = EOS;
  1395.   }
  1396.   if ((pth = strrchr(p, PATHCHAR)) != NULL)
  1397.   {
  1398.     *pth++ = EOS;
  1399.     strcpy(pat,p);
  1400.   }
  1401.   else
  1402.   {
  1403.     pth = p;
  1404.     pat[0] = EOS;
  1405.   }
  1406.   if ((p = strchr(pth,'.')) != NULL)
  1407.   {
  1408.     strcpy(fty,p);
  1409.     fty[MAXEXT-1] = EOS;
  1410.     *p = EOS;
  1411.   }
  1412.   else
  1413.     fty[0] = EOS;
  1414.  
  1415.   strcpy(fna,pth);
  1416.   fna[MAXFILE-1] = EOS;
  1417.  
  1418.   if (dr)
  1419.   {
  1420.     strcpy(dr,drv);
  1421.     if (drv[0])
  1422.       strcat(dr,":");
  1423.   }
  1424.   if (pa)
  1425.   {
  1426.     strcpy(pa,pat);
  1427.     if (pat[0])
  1428.       strcat(pa, PATHSEP);
  1429.   }
  1430.   if (fn)
  1431.     strcpy(fn,fna);
  1432.   if (ft)
  1433.    strcpy(ft,fty);
  1434. }
  1435. #endif /** _FNSPLIT **/
  1436.  
  1437. #ifdef _ICMP
  1438. /* The following functions are unfortunately not avialable on all compilers */
  1439.  
  1440. /*
  1441. *** strupr - convert string to upper case.
  1442. ***
  1443. ***
  1444.  */
  1445.  
  1446. char *strupr (char *string)
  1447. {
  1448.   char *strcnvt (char *string, int flag);
  1449.  
  1450.   return (strcnvt (string, 1));
  1451. }
  1452.  
  1453. /*
  1454. *** strlwr - convert string to lower case.
  1455. ***
  1456. ***
  1457.  */
  1458.  
  1459. char *strlwr (char *string)
  1460. {
  1461.   char *strcnvt (char *string, int flag);
  1462.  
  1463.   return (strcnvt (string, 0));
  1464. }
  1465.  
  1466. /*
  1467. *** strcnvt - convert string to upper (flag == 1) or lower (flag == 0) case.
  1468. ***
  1469. ***
  1470.  */
  1471.  
  1472. char *strcnvt (char *string, int flag)
  1473. {
  1474.   register i = 0;
  1475.  
  1476.   while (string[i])
  1477.   {  
  1478.     string[i] = (flag)?toupper (string[i]):tolower (string[i]);
  1479.     i++;
  1480.   }
  1481.  
  1482.   return (string);
  1483. }
  1484.  
  1485. /*
  1486. *** stricmp - same as strcmp(), but ignores case.
  1487. *** s1 and s2 are not modified.
  1488. ***
  1489.  */
  1490.  
  1491. int stricmp (const char *s1, const char *s2)
  1492. {
  1493.   return (strnicmp (s1, s2, (size_t) 80));
  1494. }
  1495.  
  1496. /*
  1497. *** strnicmp - same as strncmp(), but ignores case.
  1498. *** s1 and s2 are not modified.
  1499. ***
  1500.  */
  1501.  
  1502. int strnicmp (const char *s1, const char *s2, size_t n)
  1503. {
  1504.   char _s1[81], _s2[81];
  1505.  
  1506.   strncpy (_s1, s1, 80);
  1507.   strncpy (_s2, s2, 80);
  1508.   strupr (_s1);
  1509.   strupr (_s2);
  1510.  
  1511.   return (strncmp (_s1, _s2, n));
  1512. }
  1513. #endif /** _ICMP **/
  1514.